package com.zdb.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisParam;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zdb.common.Constant;
import com.zdb.common.Result;
import com.zdb.mapper.MessageMapper;
import com.zdb.mapper.ModelMapper;
import com.zdb.mapper.SessionMapper;
import com.zdb.pojo.LongMessage;
import com.zdb.pojo.Model;
import com.zdb.pojo.Session;
import com.zdb.pojo.dto.ContentItem;
import com.zdb.pojo.dto.PromptDto;
import com.zdb.service.AiService;
import com.zdb.util.AiLiUtil;
import com.zdb.util.SecUtil;
import io.reactivex.Flowable;
import io.reactivex.disposables.Disposable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class AiServiceImpl implements AiService {
    private static final Logger log = LoggerFactory.getLogger(AiServiceImpl.class);
    @Value("${Ali.accessKeyId}")
    private String accessKeyId;


    @Autowired
    private SessionMapper sessionMapper;
    @Autowired
    private MessageMapper messageMapper;

    @Autowired
    private ImageSynthesis imageSynthesis;
    @Autowired
    private Generation generation;
    @Autowired
    private ModelMapper modelMapper;
    @Override
    public List<Model> getModelList() {
        List<Model> models = modelMapper.selectList(null);
        return models;
    }

    @Override
    public List<Session> getSessionList() {
        Long userId = SecUtil.getUserId();
        QueryWrapper<Session> sessionQueryWrapper = new QueryWrapper<Session>()
                .eq("user_id", userId)
                .orderByDesc("created_at");
        List<Session> sessions = sessionMapper.selectList(sessionQueryWrapper);
        return sessions;
    }

    @Override
    public List<LongMessage> getMessageList(int id) {
        QueryWrapper<LongMessage> wrapper = new QueryWrapper<>();
        wrapper.eq("session_id", id)
                .orderByAsc("created_at")
                .orderByAsc("FIELD(role,'user','assistant')");
        return messageMapper.selectList(wrapper);
    }

    @Override
    public List<LongMessage> getSessionDetail(int id) {
        List<LongMessage> longMessages = messageMapper.selectList(new LambdaQueryWrapper<LongMessage>().eq(LongMessage::getSessionId, id));
        return longMessages;
    }

    @Override
    @Transactional
    public SseEmitter streamChatWithEmitter(String prompt, String model, Integer id, Boolean deepThinking) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        StringBuilder reasonBuilder = new StringBuilder();
        StringBuilder resultBuilder = new StringBuilder();
        if (id == null){
            Session  build = Session.builder()
                    .userId(Convert.convert(Integer.class, SecUtil.getUserId()))
                    .title(prompt)
                    .createdAt(DateUtil.date())
                    .build();
            sessionMapper.insert(build);
            log.info("sessionId:{}", build.getSessionId());
            Session session = sessionMapper.selectById(build.getSessionId());
            id=session.getSessionId();
        }
        Integer sessionId = messageMapper.selectCount(new QueryWrapper<LongMessage>().eq("session_id", id));
        if (sessionId ==0){
            Session session = sessionMapper.selectOne(new QueryWrapper<Session>().eq("session_id", id));
            session.setTitle( prompt);
            sessionMapper.update(session, new QueryWrapper<Session>().eq("session_id", id));
        }
        List<LongMessage> messageList = getMessageList(id);
        LongMessage user = buildMessage(prompt, "user",id);
        messageList.add(user);
        GenerationParam generationParam = AiLiUtil.createGenerationParam(messageList, model, accessKeyId, true, deepThinking);

        Disposable disposable = null;
        try {
            Flowable<GenerationResult> flowable = generation.streamCall(generationParam);
            log.info("流式输出:{}", flowable);
            int finalId = id;
            disposable = flowable.subscribe(
                    result -> {
                        if (result.getOutput() != null && result.getOutput().getChoices() != null
                                && !result.getOutput().getChoices().isEmpty()) {
                            String reasonContent=result.getOutput().getChoices().get(0).getMessage().getReasoningContent();
                            log.info("思考:{}", reasonContent);
                            String content = result.getOutput().getChoices().get(0).getMessage().getContent();
                            resultBuilder.append(content);
                            reasonBuilder.append(reasonContent);
                            sseEmitter.send(SseEmitter.event().data(
                                    LongMessage.builder()
                                            .sessionId(finalId)
                                            .role("assistant")
                                            .reasonContent(reasonContent)
                                            .content(content)
                                            .build()
                            ));
                        }

                    },
                    error -> {
                        log.error("流式输出中产生错误:{}", error.getMessage());
                        sseEmitter.completeWithError(error);
                    },
                    () -> {
                        messageMapper.insert(
                                LongMessage.builder()
                                        .sessionId(finalId)
                                        .role("user")
                                        .content(prompt)
                                        .build()
                        );
                        messageMapper.insert(
                                LongMessage.builder()
                                        .sessionId(finalId)
                                        .role("assistant")
                                        .reasonContent(reasonBuilder.toString())
                                        .content(resultBuilder.toString())
                                        .build()
                        );
                        log.info("流式输出结束");
                        sseEmitter.complete();
                    }
            );
        }catch (Exception e){
            log.error("调用流式接口失败:{}", e.getMessage());
        }finally {
            Disposable finalDisposable = disposable;
            sseEmitter.onCompletion(() -> {
                finalDisposable.dispose();
            });
            sseEmitter.onTimeout(() -> {
                finalDisposable.dispose();
            });
        }
        return sseEmitter;
    }
    @Override
    public Flux<Result> sendStream(String prompt, String model, Integer id, Boolean deepThinking) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        StringBuilder reasonBuilder = new StringBuilder();
        StringBuilder resultBuilder = new StringBuilder();
        if (id == null){
            Session  build = Session.builder()
                    .userId(Convert.convert(Integer.class, SecUtil.getUserId()))
                    .title(prompt)
                    .createdAt(DateUtil.date())
                    .build();
            sessionMapper.insert(build);
            log.info("sessionId:{}", build.getSessionId());
            Session session = sessionMapper.selectById(build.getSessionId());
            id=session.getSessionId();
        }
        Integer sessionId = messageMapper.selectCount(new QueryWrapper<LongMessage>().eq("session_id", id));
        if (sessionId ==0){
            Session session = sessionMapper.selectOne(new QueryWrapper<Session>().eq("session_id", id));
            session.setTitle( prompt);
            sessionMapper.update(session, new QueryWrapper<Session>().eq("session_id", id));
        }
        List<LongMessage> messageList = getMessageList(id);
        LongMessage user = buildMessage(prompt, "user",id);
        messageList.add(user);
        GenerationParam generationParam = AiLiUtil.createGenerationParam(messageList, model, accessKeyId, true, deepThinking);
        try {
            Flowable<GenerationResult> generationResultFlowable = generation.streamCall(generationParam);
            int finalId = id;
            return Flux.from(generationResultFlowable)
                    .map(result -> {
                        String reasonContent = null;
                        String content = null;
                        if (result.getOutput() != null && result.getOutput().getChoices() != null
                                && !result.getOutput().getChoices().isEmpty()) {
                            reasonContent = result.getOutput().getChoices().get(0).getMessage().getReasoningContent();
                            log.info("思考:{}", reasonContent);
                            content = result.getOutput().getChoices().get(0).getMessage().getContent();
                            resultBuilder.append(content);
                            reasonBuilder.append(reasonContent);

                        }
                        return Result.sucess("", LongMessage.builder()
                                .sessionId(finalId)
                                .role("assistant")
                                .reasonContent(reasonContent)
                                .content(content)
                                .build());
                    })
                    .doOnComplete(()->{
                        messageMapper.insert(
                                LongMessage.builder()
                                        .sessionId(finalId)
                                        .role("user")
                                        .content(prompt)
                                        .build()
                        );
                        messageMapper.insert(
                                LongMessage.builder()
                                        .sessionId(finalId)
                                        .role("assistant")
                                        .reasonContent(reasonBuilder.toString())
                                        .content(resultBuilder.toString())
                                        .build()
                        );
                        log.info("流式输出结束");
                    }).doOnError(error->{
                        log.info("error:{}",error.getMessage());
                    });
        }catch (Exception e){
            return null;
        }
    }


    @Override
    public Result imageGet(String prompt, String model, Integer id) {
        ArrayList<LongMessage> longMessages = new ArrayList<>();
        longMessages.add(LongMessage.builder()
                .role("user")
                .content( prompt)
                .build());
        ImageSynthesisParam imageSynthesisParam = AiLiUtil.createImageSynthesisParam(longMessages, model, accessKeyId, false, false);
        ImageSynthesisResult call=null;
        try {
             call = imageSynthesis.call(imageSynthesisParam);
        } catch (Exception e) {
            log.error("调用AIGC接口异常:{}",e.getMessage());
        }
        log.info("imageSynthesisResult:{}", call);
        return Result.sucess(call.getOutput().getResults().get(0).get("url"));
    }



    @Override
    public Session createSession() {
        Session build = Session.builder()
                .userId(Convert.convert(Integer.class, SecUtil.getUserId()))
                .title("新对话")
                .createdAt(DateUtil.date())
                .build();
         sessionMapper.insert(build);

         return build;
    }


    public LongMessage buildMessage(String message,String role,Integer id){
        return LongMessage.builder()
                .role(role)
                .sessionId(id)
                .content(message)
                .build();
    }
}
